package org.dht.com.tra.nw;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;
import org.dht.com.msg.MalformedMessageException;
import org.dht.com.msg.Message;
import org.dht.com.msg.MessageXML;
import org.dht.com.tra.Communicator;

/**
 * The <code>UnicastManagerUDP</code> class implemented transfer message based
 * in UDP
 * 
 */
public class UnicastManagerUDP implements Communicator {
	/**
	 * Logger
	 */
	private static final Logger logger = Logger
			.getLogger(UnicastManagerUDP.class);
	/**
	 * Is the {@code DatagramSocket} used for sending and receiving messages.
	 */
	private DatagramSocket datagramSocket;

	/**
	 * Is the buffer used for the datagramSocket when reading a message.
	 */
	private long bufferSize;

	/**
	 * Stores the value of the port used for the UDP communication.
	 */
	private int portUdp;

	public UnicastManagerUDP(int portUdp, long bufferUdp) {
		this.portUdp = portUdp;
		this.bufferSize = bufferUdp;

		try {
			this.datagramSocket = new DatagramSocket(portUdp);
		} catch (SocketException e) {
			logger.error("Error creating DatagramSocket", e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 */
	public Message reciever() {
		DatagramPacket datagramPacket;
		String string;
		Message message;
		byte[] buffer;

		buffer = new byte[(int) bufferSize];

		datagramPacket = new DatagramPacket(buffer, buffer.length);

		try {
			datagramSocket.receive(datagramPacket);

			string = new String(datagramPacket.getData(), 0,
					datagramPacket.getLength());

			message = MessageXML.valueOf(string);

			return message;
		} catch (IOException e) {
			logger.error("Error reading DatagramSocket", e);
		} catch (MalformedMessageException e) {
			logger.error("Error reading message", e);
		}

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * co.edu.uniquindio.utils.communication.transfer.Communicator#send(co.edu
	 * .uniquindio.utils.communication.message.Message)
	 */
	public void send(Message message) {
		InetAddress destinationAddress;
		DatagramPacket datagramPacket;
		String string;

		try {
			destinationAddress = InetAddress.getByName(message
					.getMessageDestination());

			string = message.toString();

			datagramPacket = new DatagramPacket(string.getBytes(),
					string.length(), destinationAddress, portUdp);

			datagramSocket.send(datagramPacket);
		} catch (UnknownHostException e) {
			logger.error("Error writting DatagramSocket", e);
		} catch (IOException e) {
			logger.error("Error writting DatagramSocket", e);
		}
	}

	/**
	 * Gets port UDP
	 * 
	 * @return Port UDP
	 */
	public int getPortUdp() {
		return portUdp;
	}

	/**
	 * Sets por UDP
	 * 
	 * @param portUdp
	 *            Port UDP
	 */
	public void setPortUdp(int portUdp) {
		this.portUdp = portUdp;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see co.edu.uniquindio.utils.communication.transfer.Stoppable#stop()
	 */
	public void stop() {
		datagramSocket.close();
	}

}
